#include "sock.h"

server_t openServer(char* addr, int port)
{
    int fd;
    server_t server;
    struct sockaddr_in saddr;
    pthread_t msgThread;
    
    if ((fd = socket(AF_INET,SOCK_STREAM, 0)) == -1) {
        printf("socket create failed!\n");
        
        server.status = -1;
        goto out;
    }
    
    server.addr = saddr;
    server.fd = fd;
    
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(port);
    saddr.sin_addr.s_addr = INADDR_ANY;
    
    memset(&(saddr.sin_zero), 0, 8);
    
    if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) == -1) {
        printf("bind error!\n");
        
        server.status = -1;
        goto out;
    }
    
    if (listen(fd, BACKLOG) == -1) {
        printf("listen error");
        
        server.status = -1;
        goto out;
    }

    messageQueue = createQueue();

    if (messageQueue == NULL) {
        close(server.fd);
        server.status = -1;
        goto out;
    }

    userList = initUserList();

    if (userList == NULL) {
        close(server.fd);
        server.status = -1;
    }

    int ret = pthread_create(&msgThread, NULL, messageThread, NULL);

    if (ret != 0 ) {
        close(server.fd);
        server.status = -1;
    }

    server.status = 0;
out:
    return server;
}

int connectServer(char* addr, int port)
{
    int fd;
    
    struct sockaddr_in serv_addr;
    
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("socket create failed!\n");
        return -1;
    }
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = inet_addr(addr);
    
    if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1 ) {
        printf("connect error.\n");
        return -1;
    }
    
    return fd;
}

void newConnect(int fd)
{
    user_t user;
    if (read(fd, (void *)&user, sizeof(user_t)) < 0) {
        
        printf("error connecttion.\n");
        close(fd);
        return;
    }

    message_t msg;
    memset((void*) &msg, 0, sizeof(message_t));
    
    msg.id = fd;
    user.conn = fd;
    
    sprintf(msg.info, "Wellcom, %s.", user.name);
    
    if (send(fd, (void *)&msg, sizeof(message_t), 0) == -1) {
        printf("error send: %s", user.name);
    } else {
        int ret = pthread_create(&(user.thread), NULL, connectionThread, (void *)&user);
        if (ret != 0) {
            printf("Can't create thread for user %s", user.name);
            close(fd);
        } else {
            insertUser(userList, user);
            printf("Received a connection from %s\n", user.name);
        }
    }

}

void * connectionThread(void * arg)
{
    puser user = (puser) arg;
    message_t msg;
    int ret;

    while (1) {
        memset((void *)&msg, 0, sizeof(message_t));
        if ((ret = read(user->conn, (void *)&msg, sizeof(message_t))) > 0) {
            enQueue(messageQueue, msg);
            printf("msg length: %d, msg: %s\n", messageQueue->length, msg.info);
        }
//        else {
//            printf("Read error: %d, %s\n", user->conn, strerror(errno));
//        }

        if (strcmp(msg.info, "exit") == 0) {
            break;
        }
        sleep(0.1);
    }

    deleteUser(userList, *user);
    close(user->conn);
    exit(0);
}

void * messageThread(void * arg)
{
    message_t msg;
    struct UserNode * node;

    printf("Message thread started!\n");
    while (1) {
        while (!isEmpty(messageQueue)) {
            msg = deQueue(messageQueue);
            printf("msg: %s\n", msg.info);
            node = userList->users;
            while (node != NULL) {
                write(node->user.conn, (void *)&msg, sizeof(message_t));
                node = node->next;
            }
        }
    }
}
